{ "cells": [ { "cell_type": "markdown", "id": "57a92274", "metadata": {}, "source": [ "# Solar and Wind Curtailment\n", "\n", "Renewables like wind and solar regularly produce energy in excess of demand. In order to keep supply and demand balanced on the grid, the result is \"curtailment\", or purposefully reducing output.\n", "\n", "In this notebook, we'll walk through accessing the curtailment data for CAISO" ] }, { "cell_type": "code", "execution_count": 1, "id": "3599dfce", "metadata": {}, "outputs": [], "source": [ "import gridstatus\n", "import pandas as pd\n", "import plotly.express as px\n", "import numpy as np\n", "from plotly.subplots import make_subplots\n", "import plotly.graph_objects as go" ] }, { "cell_type": "code", "execution_count": 2, "id": "4304ea16", "metadata": {}, "outputs": [], "source": [ "iso = gridstatus.CAISO()" ] }, { "cell_type": "markdown", "id": "a23c3119", "metadata": {}, "source": [ "## Get Curtailment Data\n", "\n", "First, we will query for curtailment data. CAISO publishes curtailment data starting on June 30, 2016. We use the `save_to` parameter to save the data locally, so it is easier to reload later." ] }, { "cell_type": "code", "execution_count": null, "id": "fc53269c", "metadata": {}, "outputs": [], "source": [ "df = iso.get_curtailment(start=\"Jan 1, 2020\", end=\"Nov 30, 2022\", save_to=\"curtailment/\")" ] }, { "cell_type": "markdown", "id": "bd4b87c4", "metadata": {}, "source": [ "we can easily reload the data in the curtailment folder like this. By default it loads with UTC timezone unless we specify otherwise." ] }, { "cell_type": "code", "execution_count": 3, "id": "3a92c4c4", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|██████████| 1052/1052 [00:00<00:00, 1347.85it/s]\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TimeCurtailment TypeCurtailment ReasonFuel TypeCurtailment (MWh)Curtailment (MW)
02020-01-01 08:00:00-08:00EconomicLocalSolar0.0NaN
12020-01-01 08:00:00-08:00EconomicSystemSolar27.0153.0
22020-01-01 08:00:00-08:00EconomicSystemWind6.040.0
32020-01-01 09:00:00-08:00EconomicLocalSolar78.0524.0
42020-01-01 09:00:00-08:00EconomicLocalWind7.046.0
.....................
288182022-11-17 13:00:00-08:00EconomicLocalSolar143.0273.0
288192022-11-17 13:00:00-08:00EconomicSystemSolar0.0NaN
288202022-11-17 14:00:00-08:00EconomicLocalSolar18.041.0
288212022-11-17 15:00:00-08:00EconomicSystemSolar1.09.0
288222022-11-17 16:00:00-08:00EconomicSystemSolar1.03.0
\n", "

28823 rows × 6 columns

\n", "
" ], "text/plain": [ " Time Curtailment Type Curtailment Reason Fuel Type \\\n", "0 2020-01-01 08:00:00-08:00 Economic Local Solar \n", "1 2020-01-01 08:00:00-08:00 Economic System Solar \n", "2 2020-01-01 08:00:00-08:00 Economic System Wind \n", "3 2020-01-01 09:00:00-08:00 Economic Local Solar \n", "4 2020-01-01 09:00:00-08:00 Economic Local Wind \n", "... ... ... ... ... \n", "28818 2022-11-17 13:00:00-08:00 Economic Local Solar \n", "28819 2022-11-17 13:00:00-08:00 Economic System Solar \n", "28820 2022-11-17 14:00:00-08:00 Economic Local Solar \n", "28821 2022-11-17 15:00:00-08:00 Economic System Solar \n", "28822 2022-11-17 16:00:00-08:00 Economic System Solar \n", "\n", " Curtailment (MWh) Curtailment (MW) \n", "0 0.0 NaN \n", "1 27.0 153.0 \n", "2 6.0 40.0 \n", "3 78.0 524.0 \n", "4 7.0 46.0 \n", "... ... ... \n", "28818 143.0 273.0 \n", "28819 0.0 NaN \n", "28820 18.0 41.0 \n", "28821 1.0 9.0 \n", "28822 1.0 3.0 \n", "\n", "[28823 rows x 6 columns]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = gridstatus.load_folder(\"curtailment\", time_zone=gridstatus.CAISO.default_timezone)\n", "df" ] }, { "cell_type": "markdown", "id": "9b816252", "metadata": {}, "source": [ "next, let's reformat the data to make it easier to work with\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "3724561f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Local Solar Curtailment (MWh)Local Wind Curtailment (MWh)System Solar Curtailment (MWh)System Wind Curtailment (MWh)Total Solar Curtailment (MWh)Total Wind Curtailment (MWh)Total Curtailment (MWh)
Time
2020-01-01 08:00:00-08:000.00.027.06.027.06.033.0
2020-01-01 09:00:00-08:0078.07.0138.013.0216.020.0236.0
2020-01-01 10:00:00-08:0012.00.0917.043.0929.043.0972.0
2020-01-01 11:00:00-08:0019.00.01229.044.01248.044.01292.0
2020-01-01 12:00:00-08:00216.025.01194.0131.01410.0156.01566.0
........................
2022-11-17 12:00:00-08:0095.00.00.00.095.00.095.0
2022-11-17 13:00:00-08:00143.00.00.00.0143.00.0143.0
2022-11-17 14:00:00-08:0018.00.00.00.018.00.018.0
2022-11-17 15:00:00-08:000.00.01.00.01.00.01.0
2022-11-17 16:00:00-08:000.00.01.00.01.00.01.0
\n", "

25233 rows × 7 columns

\n", "
" ], "text/plain": [ " Local Solar Curtailment (MWh) \\\n", "Time \n", "2020-01-01 08:00:00-08:00 0.0 \n", "2020-01-01 09:00:00-08:00 78.0 \n", "2020-01-01 10:00:00-08:00 12.0 \n", "2020-01-01 11:00:00-08:00 19.0 \n", "2020-01-01 12:00:00-08:00 216.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 95.0 \n", "2022-11-17 13:00:00-08:00 143.0 \n", "2022-11-17 14:00:00-08:00 18.0 \n", "2022-11-17 15:00:00-08:00 0.0 \n", "2022-11-17 16:00:00-08:00 0.0 \n", "\n", " Local Wind Curtailment (MWh) \\\n", "Time \n", "2020-01-01 08:00:00-08:00 0.0 \n", "2020-01-01 09:00:00-08:00 7.0 \n", "2020-01-01 10:00:00-08:00 0.0 \n", "2020-01-01 11:00:00-08:00 0.0 \n", "2020-01-01 12:00:00-08:00 25.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 0.0 \n", "2022-11-17 13:00:00-08:00 0.0 \n", "2022-11-17 14:00:00-08:00 0.0 \n", "2022-11-17 15:00:00-08:00 0.0 \n", "2022-11-17 16:00:00-08:00 0.0 \n", "\n", " System Solar Curtailment (MWh) \\\n", "Time \n", "2020-01-01 08:00:00-08:00 27.0 \n", "2020-01-01 09:00:00-08:00 138.0 \n", "2020-01-01 10:00:00-08:00 917.0 \n", "2020-01-01 11:00:00-08:00 1229.0 \n", "2020-01-01 12:00:00-08:00 1194.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 0.0 \n", "2022-11-17 13:00:00-08:00 0.0 \n", "2022-11-17 14:00:00-08:00 0.0 \n", "2022-11-17 15:00:00-08:00 1.0 \n", "2022-11-17 16:00:00-08:00 1.0 \n", "\n", " System Wind Curtailment (MWh) \\\n", "Time \n", "2020-01-01 08:00:00-08:00 6.0 \n", "2020-01-01 09:00:00-08:00 13.0 \n", "2020-01-01 10:00:00-08:00 43.0 \n", "2020-01-01 11:00:00-08:00 44.0 \n", "2020-01-01 12:00:00-08:00 131.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 0.0 \n", "2022-11-17 13:00:00-08:00 0.0 \n", "2022-11-17 14:00:00-08:00 0.0 \n", "2022-11-17 15:00:00-08:00 0.0 \n", "2022-11-17 16:00:00-08:00 0.0 \n", "\n", " Total Solar Curtailment (MWh) \\\n", "Time \n", "2020-01-01 08:00:00-08:00 27.0 \n", "2020-01-01 09:00:00-08:00 216.0 \n", "2020-01-01 10:00:00-08:00 929.0 \n", "2020-01-01 11:00:00-08:00 1248.0 \n", "2020-01-01 12:00:00-08:00 1410.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 95.0 \n", "2022-11-17 13:00:00-08:00 143.0 \n", "2022-11-17 14:00:00-08:00 18.0 \n", "2022-11-17 15:00:00-08:00 1.0 \n", "2022-11-17 16:00:00-08:00 1.0 \n", "\n", " Total Wind Curtailment (MWh) \\\n", "Time \n", "2020-01-01 08:00:00-08:00 6.0 \n", "2020-01-01 09:00:00-08:00 20.0 \n", "2020-01-01 10:00:00-08:00 43.0 \n", "2020-01-01 11:00:00-08:00 44.0 \n", "2020-01-01 12:00:00-08:00 156.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 0.0 \n", "2022-11-17 13:00:00-08:00 0.0 \n", "2022-11-17 14:00:00-08:00 0.0 \n", "2022-11-17 15:00:00-08:00 0.0 \n", "2022-11-17 16:00:00-08:00 0.0 \n", "\n", " Total Curtailment (MWh) \n", "Time \n", "2020-01-01 08:00:00-08:00 33.0 \n", "2020-01-01 09:00:00-08:00 236.0 \n", "2020-01-01 10:00:00-08:00 972.0 \n", "2020-01-01 11:00:00-08:00 1292.0 \n", "2020-01-01 12:00:00-08:00 1566.0 \n", "... ... \n", "2022-11-17 12:00:00-08:00 95.0 \n", "2022-11-17 13:00:00-08:00 143.0 \n", "2022-11-17 14:00:00-08:00 18.0 \n", "2022-11-17 15:00:00-08:00 1.0 \n", "2022-11-17 16:00:00-08:00 1.0 \n", "\n", "[25233 rows x 7 columns]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[\"Type\"] = (\n", " df[\"Curtailment Reason\"].str.lower().str.capitalize()\n", " + \" \"\n", " + df[\"Fuel Type\"]\n", " + \" Curtailment (MWh)\"\n", " )\n", "curtailment = df.pivot_table(\n", " values=\"Curtailment (MWh)\", index=\"Time\", columns=\"Type\"\n", " ).fillna(\n", " 0\n", " )\n", "\n", "curtailment[\"Total Solar Curtailment (MWh)\"] = curtailment[\"Local Solar Curtailment (MWh)\"] + curtailment[\"System Solar Curtailment (MWh)\"] \n", "curtailment[\"Total Wind Curtailment (MWh)\"] = curtailment[\"Local Wind Curtailment (MWh)\"] + curtailment[\"System Wind Curtailment (MWh)\"] \n", "curtailment[\"Total Curtailment (MWh)\"] = curtailment[\"Total Solar Curtailment (MWh)\"] + curtailment[\"Total Wind Curtailment (MWh)\"]\n", "curtailment.columns.name = None\n", "curtailment = curtailment.resample(\"1H\").sum()\n", "curtailment" ] }, { "cell_type": "markdown", "id": "e99733e3", "metadata": {}, "source": [ "## Visualizing Curtailment" ] }, { "cell_type": "markdown", "id": "50a5085d", "metadata": {}, "source": [ "#### Monthly Curtailment" ] }, { "cell_type": "code", "execution_count": 5, "id": "ed6b9ee4", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": "Jul 2020Jan 2021Jul 2021Jan 2022Jul 2022050k100k150k200k250k300k350k400k450kTotal Solar Curtailment (MWh)Total Wind Curtailment (MWh)Monthly Solar and Wind Curtailment in CAISO (MWh)TimeCurtailment (MWh)" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "monthly = curtailment.resample(\"M\").sum()\n", "monthly[\"Month\"] = monthly.index.month\n", "monthly[\"Year\"] = monthly.index.year\n", "\n", "fig = px.bar(monthly, \n", " x=monthly.index, \n", " y=[\"Total Solar Curtailment (MWh)\", \"Total Wind Curtailment (MWh)\"],\n", " title=\"Monthly Solar and Wind Curtailment in CAISO (MWh)\")\n", " \n", "# legend upper left corner\n", "fig.update_layout(legend=dict(\n", " orientation=\"h\",\n", " yanchor=\"bottom\",\n", " y=1.02,\n", " xanchor=\"left\",\n", " x=0,\n", " title_text=None\n", "))\n", "fig.update_yaxes(title_text=\"Curtailment (MWh)\")\n", "fig.show(\"svg\", width=1200, height=600)" ] }, { "cell_type": "markdown", "id": "d00a5e66", "metadata": {}, "source": [ "#### Average Hourly Curtailment" ] }, { "cell_type": "code", "execution_count": 6, "id": "a4a70869", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": "051015200100200300400500variableTotal Solar Curtailment (MWh)Total Wind Curtailment (MWh)Average Hourly Solar and Wind Curtailment in CAISO (MWh)TimeCurtailment (MWh)" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "avg_hourly = curtailment.groupby(curtailment.index.hour).mean()\n", "fig = px.line(avg_hourly,\n", " x=avg_hourly.index,\n", " y=[\"Total Solar Curtailment (MWh)\", \"Total Wind Curtailment (MWh)\"],\n", " title=\"Average Hourly Solar and Wind Curtailment in CAISO (MWh)\")\n", "fig.update_yaxes(title_text=\"Curtailment (MWh)\") \n", "fig.show(\"svg\", width=1200, height=600)" ] }, { "cell_type": "code", "execution_count": 7, "id": "9474c2be", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": "202020212022 YTD00.5M1M1.5M2MTotal Solar Curtailment (MWh)Total Wind Curtailment (MWh)Total Solar and Wind Curtailment in CAISO (MWh)YearCurtailment (MWh)" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "curtailment[\"Year\"] = curtailment.index.year\n", "yearly_sum = curtailment.groupby(\"Year\").sum()\n", "index = yearly_sum.index.astype(str).tolist()\n", "index[-1] = \"2022 YTD\"\n", "yearly_sum.index = index\n", "\n", "fig = px.bar(yearly_sum,\n", " x=yearly_sum.index, y=[\"Total Solar Curtailment (MWh)\", \"Total Wind Curtailment (MWh)\"],\n", " title=\"Total Solar and Wind Curtailment in CAISO (MWh)\",)\n", "fig.update_layout(legend=dict(\n", " yanchor=\"bottom\",\n", " y=.9,\n", " xanchor=\"left\",\n", " x=0,\n", " title_text=None\n", "))\n", "fig.update_yaxes(title_text=\"Curtailment (MWh)\")\n", "fig.update_xaxes(title_text=\"Year\")\n", "fig.show(\"svg\", width=1200, height=600)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.2" }, "vscode": { "interpreter": { "hash": "49f14642123d0cc1afa9fa45716ed5f1e915189c28b01efe02a8b7ec3c0a3fce" } } }, "nbformat": 4, "nbformat_minor": 5 }